﻿using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Xml.Linq;
using SharePointOfView.SPReporting.Silverlight.Common;
using System.Windows.Controls.DataVisualization.Charting;

namespace SharePointOfView.SPReporting.Silverlight
{
    public partial class Page : UserControl
    {
        private XDocument sourceDoc;
        private readonly string reportUrl;
        private Report.ChartSeries chartSerie;

        /// <summary>
        /// Initialize a new control that display a reporting chart
        /// </summary>
        /// <param name="reportUrl">Report's Url</param>
        public Page(string reportUrl)
        {
            InitializeComponent();
            this.reportUrl = reportUrl;
            Loaded += Page_Loaded;
        }

        /// <summary>
        /// On Load, read the report (XML document) asynchronously for treatment
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Page_Loaded(object sender, RoutedEventArgs e)
        {
            var wc = new WebClient();
            // Bind to event
            wc.OpenReadCompleted += wc_OpenReadCompleted;
            // Async call
            wc.OpenReadAsync(new Uri(reportUrl));
        }

        /// <summary>
        /// When read is completed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                // TODO : Localization
                Message.Text = "Report loaded successfully";

                using (Stream s = e.Result)
                {
                    sourceDoc = XDocument.Load(s);

                    if (sourceDoc.Root != null)
                    {
                        string chartTitle = (string)sourceDoc.Root.Attribute("Name") ?? "Report";
                        string legendTitle = (string)sourceDoc.Root.Attribute("LegendTitle") ?? "Report";
                        string chartTypeString = (string)sourceDoc.Root.Attribute("ChartType") ?? "Pie";
                        chartSerie = (Report.ChartSeries)Enum.Parse(typeof(Report.ChartSeries), chartTypeString, true);

                        ReportChart.Title = chartTitle;
                        ReportChart.LegendTitle = legendTitle;

                        var filters = from filter in sourceDoc.Descendants("Filter")
                                      select
                                          new ReportFilter
                                              {
                                                  Name = (string) filter.Attribute("Name"),
                                                  FilterAttribute = (string) filter.Attribute("FilterAttribute"),
                                                  FilterValue = (string) filter.Attribute("FilterValue")
                                              };

                        if (filters.Count() > 0)
                        {
                            CustomFilters.ItemsSource = filters;
                            CustomFilters.Visibility = Visibility.Visible;
                            CustomFiltersText.Visibility = Visibility.Visible;
                            CustomFilters.SelectedIndex = 0;
                        }
                        else
                        {
                            CustomFilters.Visibility = Visibility.Collapsed;
                            CustomFiltersText.Visibility = Visibility.Collapsed;
                            BindItems(null);
                        }
                    }
                }
            }
            else
            {
                Message.Text = e.Error.Message;
            }
        }

        /// <summary>
        /// Filter and bind data when a new filter is selected
        /// </summary>
        /// <param name="sender">Event's sender</param>
        /// <param name="e">Event's arguments</param>
        private void CustomFilters_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var currentItem = CustomFilters.SelectedItem as ReportFilter;
            BindItems(currentItem);
            if (currentItem != null)
            {
                ReportChart.LegendTitle = currentItem.Name;
//                ReportChart.Refresh();
            }
        }

        /// <summary>
        /// Bind Items
        /// </summary>
        /// <param name="filter">Current report filter</param>
        private void BindItems(ReportFilter filter)
        {
            if (sourceDoc != null && sourceDoc.Root != null)
            {
                ReportChart.Series.Clear();
                // Special case for KPI
                if (chartSerie == Report.ChartSeries.KPI)
                {
                }
                else
                {
                    BindReportItems(filter);
                }
            }
        }

        /// <summary>
        /// Bind KPI Items
        /// </summary>
        /// <param name="filter">Current report's filter</param>
        private void BindKPIItems(ReportFilter filter)
        {
            ReportChart.Visibility = Visibility.Collapsed;
            KPIList.Visibility = Visibility.Visible;

            var dataSeries =
                from dataSerie in sourceDoc.Root.Elements("Series").Elements("Serie")
                select dataSerie;

            foreach (XElement dataSerie in dataSeries)
            {
                if (string.IsNullOrEmpty(filter.FilterAttribute) || (string.IsNullOrEmpty(filter.FilterValue)))
                {
                    var elts =
                        from item in dataSerie.Descendants("Item")
                        select new ReportItem
                        {
                            Name = (string)item.Attribute("Name"),
                            Value = (double)item.Attribute("Value"),
                            Date =
                                item.Attribute("Date") == null
                                    ? DateTime.Now
                                    : (DateTime)item.Attribute("Date")
                        };
                    if (elts.Count() > 0) KPIList.ItemsSource = elts;
                }
                else
                {
                    var elts =
                        from item in dataSerie.Descendants("Item")
                        where (string)item.Attribute(filter.FilterAttribute) == filter.FilterValue
                        select new ReportItem
                        {
                            Name = (string)item.Attribute("Name"),
                            Value = (double)item.Attribute("Value"),
                            Date = item.Attribute("Date") == null
                                       ? DateTime.Now
                                       : (DateTime)item.Attribute("Date")

                        };
                    if (elts.Count() > 0) KPIList.ItemsSource = elts;
                }
            }
        }

        /// <summary>
        /// Bind Report Items to chart
        /// </summary>
        /// <param name="filter">Current report's filter</param>
        private void BindReportItems(ReportFilter filter)
        {
            KPIList.Visibility = Visibility.Collapsed;
            ReportChart.Visibility = Visibility.Visible;

            bool isTimeRepresentation = false;

            var dataSeries =
                from dataSerie in sourceDoc.Root.Elements("Series").Elements("Serie")
                select dataSerie;

            foreach (XElement dataSerie in dataSeries)
            {
                string serieName = (string)dataSerie.Attribute("Name");

                DataPointSeries ds = null;

                switch (chartSerie)
                {
                    case Report.ChartSeries.Pie:
                        ds = new PieSeries();
                        break;
                    case Report.ChartSeries.Column:
                        ds = new ColumnSeries();
                        break;
                    case Report.ChartSeries.Bar:
                        ds = new BarSeries();
                        break;
                    case Report.ChartSeries.Line:
                        isTimeRepresentation = true;
                        ds = new LineSeries();
                        break;
                    case Report.ChartSeries.Scatter:
                        isTimeRepresentation = true;
                        ds = new ScatterSeries();
                        break;
                    case Report.ChartSeries.Grid:
                        /// TODO : add grid representation
                        break;
                }
                if (ds != null)
                {
                    ds.IndependentValueBinding = isTimeRepresentation ? new Binding("Date") : new Binding("Name");
                    ds.DependentValueBinding = new Binding("Value");
                    ds.Title = serieName;
                    ds.IsSelectionEnabled = true;

                    int resultsCount = 0;

                    if (string.IsNullOrEmpty(filter.FilterAttribute) || (string.IsNullOrEmpty(filter.FilterValue)))
                    {
                        var elts =
                            from item in dataSerie.Descendants("Item")
                            select new ReportItem
                            {
                                Name = (string)item.Attribute("Name"),
                                Value = (double)item.Attribute("Value"),
                                Date =
                                    item.Attribute("Date") == null
                                        ? DateTime.Now
                                        : (DateTime)item.Attribute("Date")
                            };

                        if (elts.Count() > 0) ds.ItemsSource = elts;
                    }
                    else
                    {
                        var elts =
                            from item in dataSerie.Descendants("Item")
                            where (string)item.Attribute(filter.FilterAttribute) == filter.FilterValue
                            select new ReportItem
                            {
                                Name = (string)item.Attribute("Name"),
                                Value = (double)item.Attribute("Value"),
                                Date = item.Attribute("Date") == null
                                           ? DateTime.Now
                                           : (DateTime)item.Attribute("Date")

                            };
                        if (elts.Count() > 0) ds.ItemsSource = elts;
                    }

                    if (ds.ItemsSource != null) ReportChart.Series.Add(ds);
                }
            }
        }
    }
}
